#include <cmath>

 #include "hormigas.h"
Hormigas::Hormigas () {}

/** Constructor
* @param listado de los rect?ngulos a empaquetar
  @param contenedor
* */
Hormigas::Hormigas( list <Rectangulo> lista, Contenedor & C_): Heuristica (lista) {
   srand((unsigned)time(0));
   T = lista.size();
   cout << "Hormigas::Constructor(listado) con lista de tama?o= " << T << endl;
   candidatos = lista;
   iteracion =  iteracionSinCambio = 0;
   mejorSol = INT_MAX;
   if (lista.size() <=10) 
     N = lista.size()/2;
   else
     //N = lista.size()*20/100;
     N = log(lista.size());
   cout << "El n?mero de individuos ser? = " << N << endl;
   
   // Inicializaci?n de incremento y rastro
   for (int i = 0; i < (2*T)+1; i++) {
     vector <double> row;
     vector <double> row2;
     for (int j = 0; j < (2*T)+1; j++) {  
        row.push_back (0.0);
	row2.push_back((double) RASTRO_INICIAL);
     }
     incremento.push_back(row);
     rastro.push_back(row2);
   }
   //Inicializar rastro.
/*   for (int i = 0;  i < (2*T)+1; i++) {
     for ( int j = 1; j < (2*T)+1; j++) {
        if ( i != j)
	   rastro [i][j] = (double) RASTRO_INICIAL;
     }
   }*/
   C = C_;
   for ( int i = 0; i < N; i++){
	  Solucion s = Solucion();
      hormiga.push_back(s);
   }
}

double Hormigas::Sumar_t_n (int origen){
  double suma = 0.0;
  list<Rectangulo>::iterator it,it2;
  for (it = candidatos.begin(); it != candidatos.end(); it++) {
	 // Sumamos los candidatos normal
     int destino = it-> getid()+1;
     suma += (rastro[origen][destino])*( 1.0 / it->geth());
     //Sumamos los candidatos rotados.
     it -> rotar();
     destino += T;
     suma += (rastro[origen][destino])*( 1.0 / it->geth());
     it -> rotar();
  }
  return suma;
}

int Hormigas:: elegir_rectangulo(int origen) {
  vector <double> p;
  double suma = 0.0;
  list<Rectangulo>::iterator it;
  double denominador = Sumar_t_n(origen);
  for ( it = candidatos.begin(); it != candidatos.end(); it++) {
	  int destino = it ->getid()+1; 
	  double probabilidad = (rastro[origen][destino])*(1.0/it->geth());
	  probabilidad = probabilidad / denominador;
	  suma += probabilidad;
	  p.push_back(suma);
	  
	  // Ahora rotamos:
      it -> rotar();
	  destino += T;
	  probabilidad = (rastro[origen][destino])*(1.0/it->geth());
	  it -> rotar();
	  probabilidad = probabilidad / denominador;
	  suma += probabilidad;
	  p.push_back(suma);
  }
  // Elegimos: 
  double aleatorio = ((double)rand())/((double) RAND_MAX);
  for (int i = 0; i < p.size(); i++) {
    if (p[i] >= aleatorio)
       return i;
  }
  return 0;
}

void Hormigas:: lista( list<Rectangulo> l) {        
   int je;
   cout << "Lista: ";
   list <Rectangulo>::iterator it;
   for ( it=l.begin() ; it != l.end(); it++ ) {
      cout << ", " << (*it).getid();
      if ( it-> isRotado())
         cout <<"r";
    }
    cout << endl;
}


void Hormigas:: Listar(vector < vector< double> > h) {
   int je;
   for (int i = 0; i < (2*T)+1; i++) {
     for (int j = 0; j < (2*T)+1; j++) {
       cout << h[i][j] << " ";
     } cout << endl;}
}
  
  
void Hormigas::calcular_incremento_rastro(int Lk) {
  int origen = 0;
  list <Rectangulo>::iterator it;
  for (it = solucion.begin(); it != solucion.end(); it++) {
    int destino;
	if ( it -> isRotado())
	   destino = it -> getid()+1+T;
	else
       destino = it -> getid()+1;
    incremento [origen][destino] += (double) Q / (double) Lk;
    origen = destino;
  }
}

void Hormigas:: actualizar_rastro() {
	for (int i = 0; i < (2*T)+1; i++) {
	  for (int j = 0; j < (2*T)+1; j++) {
         double aux = ((double) RASTRO_NO_EVAPORADO * rastro[i][j]) + (incremento[i][j]);
         rastro[i][j] = aux;
     }
  }
}


list<Rectangulo> Hormigas::generaInicial() {
   int origen = 0;
   for (int k = 0; k < hormiga.size(); k++) {
      reiniciaSolucion();
      list <Rectangulo>::iterator it = candidatos.begin();
      while (!candidatos.empty()) {
        int pos = elegir_rectangulo(origen);
        it = candidatos.begin();
        for (int i = 0; i < (pos/2); i++)
          it++;
        if ((pos % 2) == 1){
	        it -> rotar();
	        origen = it -> getid()+1+T;
        }
        else 
           origen = it -> getid()+1;
        aSolucion(it);
      }
      hormiga[k].setLista(solucion);
      hormiga[k].setValor(C.calcularAltura(solucion));
      calcular_incremento_rastro(hormiga[k].getValor());
   }
   actualizar_rastro();
   sort( hormiga.begin(),hormiga.end());
   return hormiga[0].getLista();
}



list<Rectangulo> Hormigas::mejoraSolucion() {
  return(generaInicial());
  
}